package com.zhoug.common3.utils.bundle;

import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.util.Size;
import android.util.SizeF;
import android.util.SparseArray;

import com.zhoug.common3.utils.CollectionUtils;
import com.zhoug.common3.utils.LogUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Locale;

import androidx.annotation.RequiresApi;

/**
 * Bundle包装类,异常捕获
 * 本地拒绝服务攻击:应用程序在编写过程中没有对getXXXExtra()这类方法调
 * 用进行异常的捕获，攻击者可以通过发送空数据、异常数据或畸形数据使程序崩溃，从而造成拒绝服务攻击
 *
 * @Author 35574
 * @Date 2021/10/25
 * @Description
 */
public class BundleWrap {
    private static final String TAG = ">>>BundleWrap";
    private Bundle bundle;

    private BundleWrap(Bundle bundle) {
        this.bundle = bundle;
    }

    public static BundleWrap with(Bundle bundle) {
        return new BundleWrap(bundle);
    }

    public String getString(String key) {
        try {
            return bundle == null ? null : bundle.getString(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getString(String key, String defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getString(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public int getInt(String key) {
        try {
            return bundle == null ? 0 : bundle.getInt(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public int getInt(String key, int defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getInt(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public float getFloat(String key) {
        try {
            return bundle == null ? 0 : bundle.getFloat(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public float getFloat(String key, float defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getFloat(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public double getDouble(String key) {
        try {
            return bundle == null ? 0 : bundle.getDouble(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public double getDouble(String key, double defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getDouble(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public short getShort(String key) {
        try {
            return bundle == null ? 0 : bundle.getShort(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public short getShort(String key, short defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getShort(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public boolean getBoolean(String key) {
        try {
            return bundle != null && bundle.getBoolean(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean getBoolean(String key, boolean defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getBoolean(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    public byte getByte(String key) {
        try {
            return bundle == null ? 0 : bundle.getByte(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public byte getByte(String key, byte defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getByte(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public char getChar(String key) {
        try {
            return bundle == null ? 0 : bundle.getChar(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public char getChar(String key, char defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getChar(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public CharSequence getCharSequence(String key) {
        try {
            return bundle == null ? null : bundle.getCharSequence(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public CharSequence getCharSequence(String key, CharSequence defaultValue) {
        try {
            return bundle == null ? defaultValue : bundle.getCharSequence(key, defaultValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @param key
     * @param classOfT 指定转化的类型
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T extends Serializable> T getSerializable(String key, Class<T> classOfT) {
        if (bundle == null) return null;
        try {
            Serializable serializable = bundle.getSerializable(key);
            if (serializable != null) {
                //a对象所对应类信息是b对象所对应的类信息的父类或者是父接口，简单理解即a是b的父类或接口
                //a和b为同一个类或同一个接口
                if (classOfT.isAssignableFrom(serializable.getClass())) {
                    return (T) serializable;
                } else {
                    LogUtils.e(TAG, String.format(Locale.CANADA, "%s不能转化成%s", serializable.getClass(), classOfT));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param key
     * @param classOfT 指定转化的类型
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T extends Parcelable> T getParcelable(String key, Class<T> classOfT) {
        if (bundle == null) return null;
        try {
            Parcelable parcelable = bundle.getParcelable(key);
            if (parcelable != null) {
                //parcelable，a是b的父类或接口
                //a和b为同一个类或同一个接口
                if (classOfT.isAssignableFrom(parcelable.getClass())) {
                    return (T) parcelable;
                } else {
                    LogUtils.e(TAG, String.format(Locale.CANADA, "%s不能转化成%s", parcelable.getClass(), classOfT));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Bundle getBundle(String key) {
        try {
            return bundle == null ? null : bundle.getBundle(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public IBinder getBinder(String key) {
        try {
            return bundle == null ? null : bundle.getBinder(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Size getSize(String key) {
        try {
            return bundle == null ? null : bundle.getSize(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public SizeF getSizeF(String key) {
        try {
            return bundle == null ? null : bundle.getSizeF(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object get(String key) {
        try {
            return bundle == null ? null : bundle.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //############# Array ##############
    public String[] getStringArray(String key) {
        try {
            return bundle == null ? null : bundle.getStringArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public int[] getIntArray(String key) {
        try {
            return bundle == null ? null : bundle.getIntArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public long[] getLongArray(String key) {
        try {
            return bundle == null ? null : bundle.getLongArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public float[] getFloatArray(String key) {
        try {
            return bundle == null ? null : bundle.getFloatArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public double[] getDoubleArray(String key) {
        try {
            return bundle == null ? null : bundle.getDoubleArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public short[] getShortArray(String key) {
        try {
            return bundle == null ? null : bundle.getShortArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] getByteArray(String key) {
        try {
            return bundle == null ? null : bundle.getByteArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public char[] getCharArray(String key) {
        try {
            return bundle == null ? null : bundle.getCharArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean[] getBooleanArray(String key) {
        try {
            return bundle == null ? null : bundle.getBooleanArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Parcelable[] getParcelableArray(String key) {
        try {
            return bundle == null ? null : bundle.getParcelableArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public CharSequence[] getCharSequenceArray(String key) {
        try {
            return bundle == null ? null : bundle.getCharSequenceArray(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String key, Class<T> classOfT) {
        try {
            SparseArray<Parcelable> parcelableSparseArray = bundle == null ? null : bundle.getSparseParcelableArray(key);
            return CollectionUtils.castSparseArray(parcelableSparseArray, classOfT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //############# ArrayList ##############

    public ArrayList<String> getStringArrayList(String key) {
        try {
            return bundle == null ? null : bundle.getStringArrayList(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public ArrayList<Integer> getIntegerArrayList(String key) {
        try {
            return bundle == null ? null : bundle.getIntegerArrayList(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
        try {
            return bundle == null ? null : bundle.getCharSequenceArrayList(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String key, Class<T> classOfT) {
        try {
            ArrayList<Parcelable> parcelables = bundle == null ? null : bundle.getParcelableArrayList(key);
            return CollectionUtils.castArrayList(parcelables, classOfT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
